<template>
  <div class="panelBody">
    <div class="header">
      <el-select v-model="state.curSelect" style="width: 100px">
        <el-option label="表单数据" value="data"></el-option>
        <el-option label="表单结构" value="tree"></el-option>
        <el-option label="表单属性" value="prop"></el-option>

        <el-option label="样式" value="style"></el-option>
      </el-select>
      <el-button type="danger" @click="handleDom(false)">删除节点</el-button>

      <el-button type="warning" @click="nodeClick(null)">取消选中</el-button>
      <!-- 
        :disabled="state.curSelect !== 'tree'"
       -->
      <el-button
        type="success"
        @click="handleDom(true)"
        :disabled="state.curSelect !== 'tree'"
        >添加节点</el-button
      >
      <el-button type="danger" @click="resetTemplate()">清空</el-button>

      <!-- 
        :disabled="state.curSelect !== 'tree'"

       -->
    </div>
    <div id="editor" class="myEditor" v-show="state.curSelect !== 'tree'"></div>
    <el-scrollbar ref="scroll" v-show="state.curSelect === 'tree'">
      <el-tree
        :props="state.treeProps"
        ref="treeDom"
        :data="state.tree"
        highlight-current
        node-key="selfIndex"
        default-expand-all
        @node-click="nodeClick"
        :indent="10"
        draggable
        @node-drop="dragEnd"
        :allow-drop="allowDrag"
        :expand-on-click-node="false"
      ></el-tree>
    </el-scrollbar>
  </div>
</template>

<script setup lang="ts">
// @ts-nocheck
import $store from "@/stores/counter"
import { getChildState } from "element-plus/es/components/tree/src/model/node"
import monaco from "../utils/userWorker"
import {
  toCamelCase,
  deepClone,
  getCustomConfig,
  getItemByAttr,
  debounce
} from "../utils/utils"
const ctx = getCurrentInstance()
const getFormModel = inject("model")
const parentState = inject("state")
const findItem = inject("findItem")
const removeCom = inject("removeCom")
const handleSelect = inject("handleSelect")
const createCom = inject("createCom")
const initRow = inject("initRow")
const initCom = inject("initCom")
const initComChild = inject("initComChild")
const treeDom: Ref<Element | null> = ref(null)
const scroll: Ref<Element | null> = ref(null)
let store = $store().state
const allowDrag = (draggingNode, dropNode, type) => {
  // if (!dropNode || !draggingNode) return false
  if (type === "inner") {
    return (
      draggingNode?.level - dropNode?.level === 1 &&
      getIndex(dropNode) &&
      getIndex(dropNode).startsWith("row")
    )
  } else {
    return (
      draggingNode?.level - dropNode?.level === 0 &&
      (draggingNode?.level <= 2 ||
        (getIndex(draggingNode?.parent) &&
          getIndex(draggingNode?.parent) === getIndex(dropNode?.parent)))
    )
  }
  // 如果 draggingNode 和 dropNode 的 level 差值不超过 1，就可以拖拽
  return Math.abs(draggingNode.level - dropNode.level) <= 1
}
// const formConf = reactive(parentState.formConf)
const state = reactive({
  curSelect: "data",
  tree: [],
  curNode: null,
  treeProps: {
    label: "labelName",
    children: "childNode",
    level: "level",
    selfIndex: "selfIndex",
    pIndex: "pIndex"
  },
  formModel: {}
  // formData: {
  //   parentName: "test",
  //   isleaf: "1",
  //   barid: "",
  //   barname: "barname",
  //   index: 666,
  //   svgBody: "<div>svgBody</div>",
  //   lightIntensity: 0.3,
  //   lightColor: "rgba(19, 206, 102, 0.8)"
  // }
})
const mySaveForm = () => {
  if (state.curSelect === "data") {
    let str = myEditor.getValue().replace(/\r?\n|\r/g, "") ?? ""
    let oriStr = JSON.stringify(getFormModel()).replace(/\r?\n|\r/g, "") ?? ""
    if (str === oriStr) return
    let val = null
    try {
      val = JSON.parse(str)
    } catch (error) {
      val = {}
    }
    ctx?.emit("changeFormData", val)
  }
  if (state.curSelect === "prop") {
    let str = myEditor.getValue().replace(/\r?\n|\r/g, "") ?? ""
    let val = null
    let oriStr = JSON.stringify(getFormConf()).replace(/\r?\n|\r/g, "") ?? ""
    if (str === oriStr) return
    try {
      val = JSON.parse(str)
    } catch (error) {
      val = {}
    }
    ctx?.emit("changeFormConf", val)
  }
}
const resetTemplate = () => {
  parentState.formConf.template = []
}
const nodeClick = (data, node, e) => {
  let tree = treeDom //?? ctx.refs["treeDom"]

  tree.value.setCurrentKey(data?.selfIndex ?? null)
  if (!data) {
    handleSelect(null)
    state.curNode = null
    return
  }

  state.curNode = tree.value.getNode(data.selfIndex)?.data ?? data ?? null
  if (!state.curNode) {
    //点击删除节点触发
    if (!node) {
      //未加载树结构 点击组件触发
    }
    handleSelect(null)
    return
  }
  if (!node) {
    if (state.curSelect === "tree") {
      let dom = document.querySelector(`[data-key=${data.selfIndex}]`)
      let top = dom.offsetTop - 40
      scroll?.value && scroll.value.scrollTo({ top: top < 0 ? 0 : top })
    }
    //点击组件触发

    return
  }

  let item = findItem(
    { selfIndex: getIndex(state.curNode) },
    true,
    undefined,
    getChildProp
  )
  let com = item?.length ? item[0][item[1]] : null
  if (!com) return
  if (com.comName) {
    handleSelect(com)
    store.curRow = null
  } else {
    handleSelect(null)
    store.curRow = com
  }
}
const getChildProp = inject("getChildProp")
const handleDom = (isAdd = true) => {
  let formConf = parentState.formConf
  try {
    if (!state.curNode) {
      if (isAdd) parentState.formConf.template.push(initRow())
    } else {
      if (
        state.curNode &&
        getIndex(state.curNode) &&
        getIndex(state.curNode).startsWith("row")
      ) {
        let item = findItem({ selfIndex: getIndex(state.curNode) }, true)
        if (!isAdd) item[0].splice(item[1], 1)
        else {
          //添加com
          let row = item[0][item[1]]
          if (row.components.length) {
            let newCom = {
              comName: row.components[row.components.length - 1].comName,
              belongParent: row.belongParent
            }
            row.components.push(initCom(newCom))
          } else {
            row.components.push(initCom({ comName: "div" }))
          }
        }
      } else {
        let item = findItem(
          { selfIndex: getIndex(state.curNode) },
          true,
          undefined,
          getChildProp
        )
        if (!isAdd) {
          if (state.curNode.pIndex && state.curNode.childNode) {
            //删除Com
            removeCom(item)
          } else {
            //删除com子元素
            item[0].splice(item[1], 1)
          }
        } else {
          if (state.curNode.pIndex && state.curNode.childNode) {
            //添加 com 子元素
            let com = item[0][item[1]]
            let newChild = null

            if (com.childNode) {
              if (com.childNode.length) {
                newChild = deepClone(com.childNode[com.childNode.length - 1])
                newChild.selfIndex =
                  newChild.comName + "_" + Math.ceil(Math.random() * 10 ** 6)
              }
              newChild = newChild ?? initComChild(com)
              com.childNode.push(newChild)
            } else {
              //自定义组件
              let propList = ["components", "template"]
              let prop = propList.find((e) => Array.isArray(com[e]))
              if (prop) {
                if (com[prop].length) {
                  newChild = deepClone(com[prop][com[prop].length - 1])
                  newChild.selfIndex =
                    newChild.selfIndex.split("_")[0] +
                    "_" +
                    Math.ceil(Math.random() * 10 ** 6)
                  if (newChild?.childNode?.length) newChild.childNode = []
                  if (newChild?.components?.length) newChild.components = []
                  //  newChild = newChild ?? initComChild(com)
                  com[prop].push(newChild)
                }
              }
            }
          }
        }
      }
      nodeClick(null)
    }
  } catch (error) {
    throw error
  }
}
const getIndex = (node, prop = "selfIndex") => {
  let index = node?.[prop] ?? node?.data?.[prop]
  return index
}
const getFormConf = () => {
  let obj = {}
  Object.keys(parentState.formConf).forEach((k) => {
    if (k !== "props" && k !== "template") {
      obj[k] = parentState.formConf[k]
    }
  })
  return obj
}
const dragEnd = (curNode, insertNode, position, e) => {
  let curIndex = getIndex(curNode)
  let insertIndex = getIndex(insertNode)
  if (!curIndex || !insertIndex) return

  let citem = findItem({ selfIndex: curIndex }, true, undefined, getChildProp)
  let pitem = insertNode.parent?.data?.selfIndex
    ? findItem(
        { selfIndex: insertNode.parent?.data?.selfIndex },
        false,
        undefined,
        getChildProp
      )
    : undefined
  let iitem = findItem(
    { selfIndex: insertIndex },
    true,
    undefined,
    getChildProp
  )
  try {
    let curCom = deepClone(citem[0][citem[1]])
    if (position === "inner" && insertIndex.startsWith("row")) {
      //插入新行

      let offsetLeft = 0
      for (let i = 0; i <= citem[1]; i++) {
        let com = citem[0][i]
        if (com.selfIndex !== curIndex)
          offsetLeft += (com.offset ?? 0) + com.span
        else {
          curCom = deepClone(com)
          offsetLeft += com.offset ?? 0
        }
      }
      parentState.curPos = iitem[1] + "," + offsetLeft
      removeCom(citem)
      createCom(curCom, undefined, iitem[0][iitem[1]])
    } else if (
      position !== "inner" &&
      curIndex.startsWith("row") &&
      insertIndex.startsWith("row")
    ) {
      //交换行
      let cindex = citem[1]
      let iindex = iitem[1]
      if (cindex < iindex) {
        //先加后删
        citem[0].splice(iindex, 0, curCom)
        citem[0].splice(cindex, 1)
      } else {
        //先删后加
        citem[0].splice(cindex, 1)
        citem[0].splice(iindex, 0, curCom)
      }
    } else if (
      position !== "inner" &&
      !curIndex.startsWith("row") &&
      !insertIndex.startsWith("row")
    ) {
      //交换com  同级
      if (
        getIndex(curNode, "pIndex") &&
        getIndex(curNode, "pIndex").startsWith("row")
      ) {
        //最外层com
        let offsetLeft = 0
        for (let i = 0; i <= iitem[1]; i++) {
          let com = iitem[0][i]
          if (com.selfIndex !== insertIndex)
            offsetLeft += (com.offset ?? 0) + com.span
          else {
            // curCom = com
            if (position === "before") {
              break
            }
            offsetLeft += (com.offset ?? 0) + com.span
          }
        }
        parentState.curPos = iitem[1] + "," + offsetLeft
        removeCom(citem)
        curCom.belongParent = iitem[0][iitem[1]].belongParent

        createCom(curCom, undefined, pitem) ////!change
      } else {
        //交换com子节点 同级
        let cindex = citem[1]
        let iindex = iitem[1]
        if (cindex < iindex) {
          //先加后删
          citem[0].splice(iindex, 0, curCom)
          citem[0].splice(cindex, 1)
        } else {
          //先删后加
          citem[0].splice(cindex, 1)
          citem[0].splice(iindex, 0, curCom)
        }
      }
    }
  } catch (error) {
    throw error
  }
}
let lastFormConf = "{}"
let lastTree = "[]"
const initTree = () => {
  let formConfStr = JSON.stringify(parentState.formConf)
  if (state.curSelect !== "tree" || lastFormConf === formConfStr) return
  let tree = []
  lastFormConf = formConfStr
  let rows = parentState.formConf?.template ?? []
  if (!Array.isArray(rows)) return
  rows.forEach((conf, r) => {
    tree.push(getLeave(conf, r, 1))
  })
  let treeStr = JSON.stringify(tree)
  if (lastTree === treeStr) return
  state.tree = tree
  lastTree = treeStr
}
const updateFormData = debounce((val) => {
  let nv = val !== "prop" ? getFormModel() : getFormConf()
  if (
    nv &&
    myEditor &&
    (state.curSelect === "data" || state.curSelect === "prop")
  ) {
    let str = myEditor.getValue().replace(/\r?\n|\r/g, "") ?? ""
    let oriStr = JSON.stringify(nv).replace(/\r?\n|\r/g, "") ?? ""
    if (str === oriStr) return
    myEditor.setValue(oriStr)
    formatter()
  }
}, 200)
const getLeave = (conf, i, level, p) => {
  let item = {
    labelName: (conf.comName ?? "row") + "_" + i,
    childNode:
      conf["template"] ?? conf["childNode"] ?? conf["components"] ?? [],
    selfIndex: conf.selfIndex ?? Math.ceil(Math.random() * 10 ** 6),
    level,
    pIndex: p?.selfIndex ?? "form"
  }

  let children = []
  if (item.childNode.length)
    item.childNode.forEach((e, r) => {
      children.push(getLeave(e, r, level + 1, item))
    })
  item.childNode = children
  return item
}
const resetLanguage = () => {
  let newVal = null
  if (state.curSelect.includes("style")) {
    newVal = "less"
  } else {
    newVal = "json"
  }
  if (newVal !== myEditor.getModel().getLanguageId()) {
    monaco.editor.setModelLanguage(myEditor.getModel(), newVal)
    myEditor.setValue("")
  }
}
const formatter = (wait = true) => {
  if (!wait) {
    myEditor.getAction("editor.action.formatDocument").run()
    return
  }
  nextTick(() => {
    myEditor.getAction("editor.action.formatDocument").run()
  })
}
const myResetField = (format = true) => {
  ////////////global????
  let val = ""
  if (state.curSelect === "data") val = getFormModel()
  let strVal = val
  if (typeof val === "function") strVal = val.toString()
  if (typeof val === "object") strVal = JSON.stringify(val)
  if (typeof val === "string" && val !== "") strVal = '"' + strVal + '"'
  strVal += ""
  myEditor.setValue(strVal)
  if (format) formatter()
}
watch(
  () => getFormModel(),
  (nv) => {
    //state.formModel = deepClone(nv)
    updateFormData()
  },
  { deep: true }
)
watch(
  () => state.curSelect,
  (nv, ov) => {
    if (nv === "data" || nv === "prop") {
      updateFormData(nv)
      initTree()
      return
    }
    if (nv !== "tree" && ov == "tree") {
    }
    if (nv == "tree") initTree()
  }
)

watch(
  () => parentState.formConf,
  (nv) => {
    initTree()
  },
  { deep: true }
)

watch(
  () => parentState.curCom?.selfIndex,
  (nv) => {
    if (nv && nv !== state.curNode?.selfIndex) {
      nodeClick({ selfIndex: nv })
    }
  }
)

let myEditor: any
onMounted(() => {
  let dom = document.getElementById("editor")
  myEditor = monaco.editor.create(dom, {
    value: "",
    language: state.curSelect === "data" ? "json" : "less",
    theme: "vs",
    validateOnType: false
  })
  myEditor.updateOptions({
    wordWrap: "on"
  })
  myEditor.onDidBlurEditorText(() => {
    //失焦保存
    formatter(false)
    mySaveForm()
    // 执行你需要的代码
  })
  setTimeout(() => myResetField(), 1000)
})
const resetLayout = debounce(() => {
  myEditor.layout()
}, 500)
window.addEventListener("resize", function () {
  resetLayout()
})
</script>

<style lang="less" scoped>
.fullContent() {
  width: 100%;
  height: 100%;
}
.flexNormal() {
  width: 100%;
  height: 100%;
  display: flex;
}
.panelBody {
  flex-direction: column;
  // overflow-y: auto;
  .flexNormal();
  .fullContent();
  .header {
    .flexNormal();
    height: fit-content;
    margin: 10px 0;
    justify-content: space-around;
  }
  .myEditor {
    height: 80%;
    margin: 2px;
  }
  .el-tree {
    overflow-y: auto;
  }
}
</style>
